(function ($) {
// Note: Chosen's browser detection has been patched in chosen.jquery.min.js
// to always return true for all browsers (except IE which needs document mode check).
// This enables Chosen on all Android devices, iPhones, and other mobile devices.
$(document).ready(function () {
// Function to enhance Chosen dropdowns for accessibility
function enhanceChosenAccessibility() {
// First, ensure all select elements have explicit labels
$('select.filter-dropdown').each(function() {
const select = $(this);
const selectId = select.attr('id');
const labelText = select.attr('data-placeholder') || 'Select an option';
// Check if there's already a label for this select
const existingLabel = $('label[for="' + selectId + '"]');
if (existingLabel.length === 0) {
// Create a visible label for SiteImprove compliance
select.before('');
}
});
// Fix empty containers that SiteImprove flags
$('div.chosen-drop, div.chosen-container, span.chosen-single span, ul.chosen-results, ul.chosen-choices').each(function() {
const container = $(this);
// Check if the container is empty
if (container.children().length === 0 && !container.text().trim()) {
// Add a hidden span with text for screen readers
const containerType = container.prop('tagName').toLowerCase();
const containerClass = container.attr('class') || '';
let placeholderText = 'Select an option';
// Determine appropriate placeholder text based on container type
if (containerClass.includes('chosen-single') && containerClass.includes('chosen-default')) {
// For default single select, use the placeholder from the original select
const originalId = container.closest('.chosen-container').attr('id').replace('_chosen', '');
const originalSelect = $('#' + originalId);
placeholderText = originalSelect.attr('data-placeholder') || 'Select an option';
} else if (containerClass.includes('chosen-results')) {
placeholderText = 'Options will appear here';
} else if (containerClass.includes('chosen-choices')) {
placeholderText = 'Selected options will appear here';
}
// Add appropriate content based on container type
if (containerType === 'ul') {
container.html('
' + placeholderText + '
');
} else {
container.html('' + placeholderText + '');
}
}
});
// Add ARIA attributes to all chosen-results lists
$(".chosen-results").each(function() {
$(this).attr({
'role': 'listbox',
'aria-live': 'polite'
});
// Add a placeholder item if the list is empty
if ($(this).children().length === 0 || ($(this).children().length === 1 && $(this).children().first().hasClass('accessibility-placeholder'))) {
$(this).html('
Items will be displayed upon interaction.
');
}
});
// Fix accessibility for each Chosen container
$(".chosen-container").each(function() {
const container = $(this);
// Get the original select element's ID by removing '_chosen' from the container ID
const originalId = container.attr('id').replace('_chosen', '');
const selectElement = $('#' + originalId);
// Skip if we can't find the original select
if (selectElement.length === 0) return;
// Find the label for this select
const existingLabel = $('label[for="' + originalId + '"]');
let labelText = selectElement.attr('data-placeholder') || 'Select an option';
// If there's an existing label, use its text
if (existingLabel.length > 0) {
labelText = existingLabel.text();
}
// Generate a unique ID for accessibility elements
const uniqueId = originalId + '-accessible';
// Ensure the original select has an explicit label with an ID
if (existingLabel.length > 0) {
existingLabel.attr('id', originalId + '-label');
} else {
// Create a label if none exists
container.before('');
}
// Add proper ARIA attributes to the container
container.attr({
'role': 'combobox',
'aria-expanded': 'false',
'aria-haspopup': 'true',
'aria-owns': uniqueId + '-results',
'aria-labelledby': originalId + '-label'
});
// Add ID to the results container
const resultsContainer = container.find('.chosen-results');
resultsContainer.attr('id', uniqueId + '-results');
// Fix the search input field
const searchField = container.find('.chosen-search-input');
if (searchField.length) {
searchField.attr({
'id': uniqueId + '-search',
'aria-label': 'Search ' + labelText,
'aria-controls': uniqueId + '-results'
});
}
// Handle single select Chosen containers
if (container.hasClass('chosen-container-single')) {
const chosenSingle = container.find('.chosen-single');
chosenSingle.attr({
'id': uniqueId,
'role': 'button',
'aria-labelledby': originalId + '-label'
});
// Add a label specifically for the a.chosen-single element that SiteImprove sees as a form control
if ($('label[for="' + uniqueId + '"]').length === 0) {
chosenSingle.before('');
}
}
// Handle multi select Chosen containers
else if (container.hasClass('chosen-container-multi')) {
const chosenChoices = container.find('.chosen-choices');
chosenChoices.attr({
'id': uniqueId,
'role': 'listbox',
'aria-labelledby': originalId + '-label'
});
// Add a label specifically for the ul.chosen-choices element
if ($('label[for="' + uniqueId + '"]').length === 0) {
chosenChoices.before('');
}
// Also label the input field inside chosen-choices that SiteImprove might flag
const inputField = chosenChoices.find('input');
if (inputField.length) {
const inputId = uniqueId + '-input';
inputField.attr('id', inputId);
if ($('label[for="' + inputId + '"]').length === 0) {
inputField.before('');
}
}
}
// Set up MutationObserver to watch for changes in the results list
if (resultsContainer.length && typeof MutationObserver !== 'undefined') {
const observer = new MutationObserver(function(mutations) {
// When results are populated, ensure there's always at least one item
if (resultsContainer.children().length === 0) {
resultsContainer.html('
Items will be displayed upon interaction.
');
} else if (resultsContainer.children().length === 1 && resultsContainer.children().first().hasClass('no-results')) {
// If "no results" is the only item, keep it but add proper role
resultsContainer.children().first().attr('role', 'option');
} else {
// Remove placeholder if real results are present
resultsContainer.find('.accessibility-placeholder').remove();
}
});
// Start observing the results container
observer.observe(resultsContainer[0], { childList: true, subtree: true });
}
});
}
// Initial enhancement with a delay to ensure Chosen has initialized
setTimeout(enhanceChosenAccessibility, 500);
// Re-apply enhancements when Chosen is updated or when dropdowns are shown
$(document).on('chosen:showing_dropdown chosen:ready chosen:updated', function() {
enhanceChosenAccessibility();
});
// Also apply when window is fully loaded (backup)
$(window).on('load', enhanceChosenAccessibility);
// Apply aria-labels to generic Learn More and Apply Now links
// ------------------------------------------------------------------
// Select all links with text "Learn More" or "Apply Now"
$('a').filter(function () {
var text = $(this).text().trim().toLowerCase();
return text === 'learn more' || text === 'apply now';
}).each(function () {
var link = $(this); // Current link element
var href = link.attr('href'); // Get the href attribute
// Check if href exists to avoid errors
if (href) {
// Extract the last part of the URL after the last slash
var slug = href.split('/').filter(function (part) {
return part.length > 0; // Remove empty parts caused by trailing slashes
}).pop();
// Determine the type of link
var linkText = link.text().trim();
var ariaLabel;
// Customize the aria-label text based on the link text
if (linkText.toLowerCase() === 'learn more') {
ariaLabel = 'Learn more about ' + slug.replace(/-/g, ' ');
} else if (linkText.toLowerCase() === 'apply now') {
ariaLabel = 'Apply now to ' + slug.replace(/-/g, ' ');
}
// Set the aria-label attribute
link.attr('aria-label', ariaLabel);
}
});
});
})(jQuery);